package copyengine.utils
{

	import com.fl.motion.AdjustColor;

	import copyengine.ui.CESprite;
	import copyengine.ui.CESpriteEvent;

	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.events.EventDispatcher;
	import flash.external.ExternalInterface;
	import flash.filters.ColorMatrixFilter;
	import flash.net.LocalConnection;
	import flash.utils.Dictionary;

	import org.as3commons.reflect.Accessor;
	import org.as3commons.reflect.Field;
	import org.as3commons.reflect.Type;
	import org.as3commons.reflect.Variable;

	public final class GeneralUtils
	{
		public function GeneralUtils()
		{
		}

		[Inline]
		public static function addTargetEventListener(_target:EventDispatcher, _type:String, _listener:Function, _useCapture:Boolean=false, _priority:int=0, _useWeakReference:Boolean=true):void
		{
			_target && _target.addEventListener(_type, _listener, _useCapture, _priority, _useWeakReference);
		}

		[Inline]
		public static function removeTargetEventListener(_target:EventDispatcher, _type:String, _listener:Function, _useCapture:Boolean=false):void
		{
			_target && _target.removeEventListener(_type, _listener, _useCapture);
		}

		public static const ADD_ORDER_TYPE_TOP:int=1;
		public static const ADD_ORDER_TYPE_LAST:int=2;

		public static function addTargetToParent(_target:DisplayObject, _parent:DisplayObjectContainer, _adjustOrder:int=ADD_ORDER_TYPE_TOP):void
		{
			if (_target != null && _parent != null)
			{
				switch (_adjustOrder)
				{
					case ADD_ORDER_TYPE_LAST:
					{
						_parent.addChildAt(_target, 0);
						break;
					}
					case ADD_ORDER_TYPE_TOP:
					{
						_parent.addChild(_target);
						break;
					}
				}
			}
		}

		public static function removeTargetFromParent(_target:DisplayObject):void
		{
			if (_target != null)
			{
				if (_target is MovieClip)
				{
					(_target as MovieClip).stop();
				}
				if (_target is CESprite)
				{
					(_target as CESprite).dispose();
				}
				if (_target.parent != null)
				{
					_target.parent.removeChild(_target);
				}
			}
		}

		/**
		 *清除并发送DisposeEvent 用于场景切换或者最后清除Mc时候调用
		 */
		public static function cleanAndDisposeTarget(_target:DisplayObjectContainer):void
		{
			if (_target)
			{
				while (_target.numChildren > 0)
				{
					var child:DisplayObject=_target.getChildAt(0);
					if (child == null || child is Loader)
					{
						break;
					}
					if (child is DisplayObjectContainer)
					{
						cleanAndDisposeTarget(child as DisplayObjectContainer);
					}
					else
					{
						removeTargetFromParent(child);
					}
				}
				if (_target.hasEventListener(CESpriteEvent.DISPOSE))
				{
					_target.dispatchEvent(new CESpriteEvent(CESpriteEvent.DISPOSE));
				}
			}
			removeTargetFromParent(_target);
		}

		/**
		 * Add one target to an array ,
		 * if the array already have the targat then return false , else return true
		 */
		public static function addElementToArrayOrVector(_element:*, _array:*):Boolean
		{
			for each (var arrayObj:* in _array)
			{
				if (arrayObj == _element)
				{
					return false
				}
			}
			_array.push(_element);
			return true;
		}

		public static function removeElementFromArrayOrVector(_element:*, _array:*):Boolean
		{
			var id:int=_array.indexOf(_element);
			if (id >= 0)
			{
				_array.splice(id, 1);
				return true;
			}
			return false;
		}

		/**
		 * <b>清空Dictionary中的所有Key值</b>
		 */
		public static function cleanDic(_dic:Dictionary):void
		{
			for (var eachKey:* in _dic)
			{
				delete _dic[eachKey];
			}
		}

		public static function swapObjectInArray(_objOneIndex:int, _objTwoIndex:int, _array:Array):void
		{
			if (_objOneIndex < _array.length && _objTwoIndex < _array.length)
			{
				var obj:Object=_array[_objOneIndex];
				_array[_objOneIndex]=_array[_objTwoIndex];
				_array[_objTwoIndex]=obj;
				obj=null;
			}
		}

		/**
		 * return a<= x <= y
		 */
		public static function isBetweenValue(_number:int, _downLine:int, _upLine:int):Boolean
		{
			if (_number >= _downLine && _number <= _upLine)
			{
				return true;
			}
			else
			{
				return false;
			}
		}

		[Inline]
		public static function normalizingValue(_val:Number, _low:Number, _hight:Number):Number
		{
			//防止low value 和 hight value 越界范围变成反向
			if (_low > _hight)
			{
				var tempValue:int=_low;
				_low=_hight;
				_hight=tempValue;
			}
			_val=Math.max(_low, _val);
			return Math.min(_val, _hight);
		}

		public static function clearChild(_dContianer:DisplayObjectContainer):void
		{
			if (_dContianer != null)
			{
				if (_dContianer is MovieClip)
				{
					(_dContianer as MovieClip).stop();
				}
				while (_dContianer.numChildren > 0)
				{
					var child:DisplayObject=_dContianer.getChildAt(0);
					removeTargetFromParent(child);
					child=null;
				}
				_dContianer=null;
			}
		}

		public static function gc():void
		{
			try
			{
				new LocalConnection().connect("gc");
				new LocalConnection().connect("gc");
			}
			catch (e:Error)
			{
				var shouldTouchHere:Boolean=true;
			}
		}

		static public function compareNumber(_n1:Number, _n2:Number, _tolerant:Number=0.1):Boolean
		{
			var diff:Number=Math.abs(_n1 - _n2);
			if (diff <= _tolerant)
			{
				return true;
			}
			return false;

		}

		// compare only date, not include time
		// return true: equal
		static public function compareDate(date1:Date, date2:Date):Boolean
		{
			var result:Boolean=false;
			if (date1 == null)
			{
				if (date2 == null)
				{
					return true;
				}

				return result;
			}

			if (date2 == null)
			{
				return result;
			}

			result=compareNumber(date1.getFullYear(), date2.getFullYear());

			if (result)
			{
				result=compareNumber(date1.getMonth(), date2.getMonth());
			}

			if (result)
			{
				result=compareNumber(date1.getDate(), date2.getDate());
			}

			return result;
		}

		static public function getCookie(cookieName:String):String
		{
			var r:String="";
			var search:String=cookieName + "=";
			var js:String="function get_cookie(){return document.cookie;}";
			var o:Object=ExternalInterface.call(js);
			var cookieVariable:String=o.toString();

			if (cookieVariable.length > 0)
			{
				var offset:int=cookieVariable.indexOf(search);
				if (offset != -1)
				{
					offset+=search.length;
					var end:int=cookieVariable.indexOf(";", offset);
					if (end == -1)
					{
						end=cookieVariable.length;
					}
					r=unescape(cookieVariable.substring(offset, end));
				}
			}
			return r;
		}

		static public function setCookie(cookieName:String, cookieValue:String):void
		{
			var js:String="function sc(){";
			js+="var c = escape('" + cookieName + "') + '=' + escape('" + cookieValue + "') + '; path=/';";
			js+="document.cookie = c;";
			js+="}";
			ExternalInterface.call(js);
		}

		/**
		 *设置UI时候可以使用，不可以使用的UI会关闭mouseChildren和mouseEnabled属性
		 * 并且用grayDisplayObject将颜色变灰
		 *
		 * @param _isEnable
		 * @param _target
		 *
		 */
		public static function changeTargetEnableProperty(_isEnable:Boolean, _target:DisplayObjectContainer):void
		{
			if (_target != null)
			{
				if (_isEnable)
				{
					_target.mouseChildren=_target.mouseEnabled=true;
					cleanDisplayObjectFilter(_target);
				}
				else
				{
					_target.mouseChildren=_target.mouseEnabled=false;
					grayDisplayObject(_target);
				}
			}
		}

		/**
		 *  将目标颜色变灰
		 */
		public static function grayDisplayObject(_obj:DisplayObject):void
		{
			if (_obj != null)
			{
				var adjColor:AdjustColor=new AdjustColor();
				adjColor.brightness=adjColor.contrast=adjColor.hue=0;
				adjColor.saturation=-100;
				_obj.filters=[new ColorMatrixFilter(adjColor.CalculateFinalFlatArray())]
			}
		}

		public static function cleanDisplayObjectFilter(_target:DisplayObject):void
		{
			if (_target != null)
			{
				_target.filters=null;
			}
		}

		public static function setDisplayObjectFilterByMc(_target:DisplayObject, _filterObject:DisplayObject):void
		{
			if (_target != null && _filterObject != null)
			{
				_target.filters=_filterObject.filters;
			}
		}

		//====================================//
		//========== Clone & 序列化与反序列化 ========//
		//====================================//
		public static function cloneObject(_obj:*):*
		{
			return doSerializeObject(_obj, SERIALIZE_TYPE_CLONE);
		}

		public static function serializeObject(_obj:*):Object
		{
			return doSerializeObject(_obj, SERIALIZE_TYPE_TRANSFER);
		}

		public static function convertToJsonObject(_obj:*):Object
		{
			return doSerializeObject(_obj, SERIALIZE_TYPE_FOR_JSON);
		}

		public static function deserializeObject(_obj:Object):*
		{
			return doDeserializeObject(_obj);
		}


		//========================================================//
		//===                                         反序列化                                                            ====//
		//========================================================//

		private static function doDeserializeObject(_transportLayerData:Object):*
		{
			var returnObjType:Type=Type.forName(_transportLayerData["classFullName"]);
			var warpObject:*=_transportLayerData["warpObject"];

			var returnObj:*=new returnObjType.clazz();
			if (returnObj is Vector.<*> || returnObj is Array)
			{
				for each (var subObject:* in warpObject)
				{
					if (subObject is String || subObject is int || subObject is uint || subObject is Number || subObject is Boolean)
					{
						returnObj.push(subObject);
					}
					else
					{
						returnObj.push(doDeserializeObject(subObject));
					}
				}
			}
			else
			{
				var cloneProperty:*=null;
				//如果classFullName为Object 则表示为动态Object
				if (_transportLayerData["classFullName"] == "Object")
				{
					for (var key:String in warpObject)
					{
						cloneProperty=doDeserializeProperty(warpObject[key], null);
						returnObj[key]=cloneProperty;
					}
				}
				else
				{
					for each (var property:Field in returnObjType.properties)
					{
						if (property is Variable || property is Accessor && Accessor(property).writeable && property.name != 'prototype')
						{
							cloneProperty=doDeserializeProperty(warpObject[property.name], property);
							returnObj[property.name]=cloneProperty;
						}
					}
				}
			}
			return returnObj;
		}

		private static function doDeserializeProperty(_sourceProperty:*, _currentField:Field):*
		{
			if (_sourceProperty != null)
			{
				if (_sourceProperty is Boolean || _sourceProperty is String || _sourceProperty is int || _sourceProperty is uint || _sourceProperty is Number)
				{
					return _sourceProperty;
				}
				else
				{
					return doDeserializeObject(_sourceProperty);
				}
			}
			else
			{
				return null;
			}
		}

		//========================================================//
		//===                                         序列化 or Clone                                                 ====//
		//========================================================//

		/**
		 *序列化类型：Clone  标示该类型则会直接深度Clone当前对象
		 */
		private static const SERIALIZE_TYPE_CLONE:int=1;

		/**
		 * 序列化类型：Transfer 标示该类型则会将当前对象转发为可以使用反序列化函数不丢失类型的转化对象
		 * 注意::只有反序列化函数才可以解析该类型对象
		 */
		private static const SERIALIZE_TYPE_TRANSFER:int=2;

		/**
		 * 序列化类型：JSON 标示该类型则会将对象转发为可以被JSON对象识别的可序列化对象
		 */
		private static const SERIALIZE_TYPE_FOR_JSON:int=3;

		/**
		 *序列化 or Clone对象
		 *
		 * 序列化后的对象及非原来对象，需要调用反序列化才可恢复 而Clone后的对象及为原始对象的Clone
		 *
		 */
		private static function doSerializeObject(_normalObj:*, _serializeType:int):Object
		{
			//注意!!::
			//原来ObjectType是部分由递归函数传入,为了简化取Type的次数,不过由于当给Type指定为"*"时候
			//logic无法取得当前_normalObj的真实Type,所以所有的Tpye都重新从_normalObj取一次
			var objType:Type=Type.forInstance(_normalObj);
			var returnCloneObj:Object;

			if (_normalObj != null)
			{
				if (_normalObj is Vector.<*> || _normalObj is Array)
				{
					returnCloneObj=doSerializeArrayAndVectorObj(_normalObj, _serializeType, objType);
				}
				else if (_normalObj is Dictionary)
				{
					returnCloneObj=doSerializeDictionaryObj(_normalObj, _serializeType, objType);
				}
				else
				{
					returnCloneObj=doSerializeNotListStructureObj(_normalObj, _serializeType, objType);
				}

				if (_serializeType == SERIALIZE_TYPE_TRANSFER)
				{
					var transportWarp:Object={}
					transportWarp["isCETransportObject"]=true;
					transportWarp["classFullName"]=objType.fullName;
					transportWarp["warpObject"]=returnCloneObj;
					return transportWarp;
				}
				else
				{
					return returnCloneObj;
				}
			}
			return null;

		}

		private static function doSerializeDictionaryObj(_normalObj:*, _serializeType:int, _objType:Type):Object
		{
			var returnCloneObj:Object;
			//如果为Clone对象则直接使用原始对象的类型
			if (_serializeType == SERIALIZE_TYPE_CLONE)
			{
				returnCloneObj=new _objType.clazz();
			}
			else if (_serializeType == SERIALIZE_TYPE_FOR_JSON)
			{
				returnCloneObj={};
			}
			//如果是序列化对象则直接存入Array(可以混存,防止原对象为混存对象)
			else
			{
				throw new Error("Can't serialize dictionary obj(but can clone) right now, as there is not space to store the key");
			}
			for (var key:Object in _normalObj)
			{
				var subObject:*=_normalObj[key];
				if (subObject is String || subObject is int || subObject is uint || subObject is Number || subObject is Boolean)
				{
					//基础类型 直接Push进去
					returnCloneObj[key]=subObject;
				}
				else
				{
					returnCloneObj[key]=doSerializeObject(subObject, _serializeType);
				}
			}
			return returnCloneObj;
		}

		/**
		 * 序列化Array or Vector结构的Object
		 */
		private static function doSerializeArrayAndVectorObj(_normalObj:*, _serializeType:int, _objType:Type):Object
		{
			var returnCloneObj:Object;
			//如果为Clone对象则直接使用原始对象的类型
			if (_serializeType == SERIALIZE_TYPE_CLONE)
			{
				returnCloneObj=new _objType.clazz();
			}
			//如果是序列化对象则直接存入Array(可以混存,防止原对象为混存对象)
			else
			{
				returnCloneObj=[];
			}
			for each (var subObject:* in _normalObj)
			{
				if (subObject is String || subObject is int || subObject is uint || subObject is Number || subObject is Boolean)
				{
					//基础类型 直接Push进去
					returnCloneObj.push(subObject);
				}
				else
				{
					returnCloneObj.push(doSerializeObject(subObject, _serializeType));
				}
			}
			return returnCloneObj;
		}

		/**
		 * 序列化不为List结构(Array,Vector,Dictonary)的Object
		 */
		private static function doSerializeNotListStructureObj(_normalObj:*, _serializeType:int, _objType:Type):Object
		{
			var returnCloneObj:Object;
			if (_serializeType == SERIALIZE_TYPE_CLONE)
			{
				returnCloneObj=new _objType.clazz();
			}
			else
			{
				returnCloneObj={}
			}
			var cloneProperty:*=null;
			//动态的情况直接for循环取出Key值
			//非动态的情况下无法for循环取Key值
			if (_objType.fullName == "Object")
			{
				for (var key:String in _normalObj)
				{
					if (_normalObj[key] != null)
					{
						cloneProperty=doSerializeProperty(_normalObj[key], _serializeType, null);
						returnCloneObj[key]=cloneProperty;
					}
				}
			}
			else
			{
				for each (var property:Field in _objType.properties)
				{
					if (property is Variable || property is Accessor && Accessor(property).writeable && property.name != 'prototype')
					{
						if (_normalObj[property.name] != null)
						{
							cloneProperty=doSerializeProperty(_normalObj[property.name], _serializeType, property);
							returnCloneObj[property.name]=cloneProperty;
						}
					}
				}
			}
			return returnCloneObj;
		}

		private static function doSerializeProperty(_sourceProperty:*, _serializeType:int, _currentField:Field):*
		{
			//如果有Field则是非动态Object,否则为动态Object
			if (_currentField)
			{
				if (_currentField is Variable || _currentField is Accessor && Accessor(_currentField).writeable && _currentField.name != 'prototype')
				{
					if (_currentField.type.fullName == "Boolean" || _currentField.type.fullName == "String" || _currentField.type.fullName == "int" || _currentField.type.fullName == "uint" || _currentField.type.fullName == "Number")
					{
						//基本类型
						return _sourceProperty;
					}
					else
					{
						return doSerializeObject(_sourceProperty, _serializeType);
					}
				}
			}
			else
			{
				if (_sourceProperty is Boolean || _sourceProperty is String || _sourceProperty is int || _sourceProperty is uint || _sourceProperty is Number)
				{
					return _sourceProperty;
				}
				else
				{
					return doSerializeObject(_sourceProperty, _serializeType);
				}
			}
		}


	}
}


